"""K线形态识别函数."""

from __future__ import annotations

import numpy as np
import pandas as pd


def _detect_candlestick_patterns(open: pd.Series, high: pd.Series, low: pd.Series, close: pd.Series) -> pd.DataFrame:
    """检测K线形态模式.
    
    识别11种常见的K线形态，包括基础形态和高级形态。
    每个形态返回0（未识别）或1（已识别）的布尔值。
    
    Parameters
    ----------
    open:
        开盘价序列
    high:
        最高价序列
    low:
        最低价序列
    close:
        收盘价序列
        
    Returns
    -------
    pd.DataFrame
        包含所有形态识别结果的DataFrame，每列对应一种形态
    """
    patterns = pd.DataFrame(index=open.index)
    
    # 计算K线的基本组成部分
    body = (close - open).abs()  # 实体大小（绝对值）
    body_size = body / close  # 实体相对大小
    upper_shadow = high - pd.concat([close, open], axis=1).max(axis=1)  # 上影线
    lower_shadow = pd.concat([close, open], axis=1).min(axis=1) - low  # 下影线
    total_range = high - low  # 总波动范围
    
    # 避免除零错误
    total_range_safe = total_range.replace(0, np.nan)
    
    # 判断是阳线还是阴线
    is_bullish = close > open  # 阳线（收盘价 > 开盘价）
    is_bearish = close < open  # 阴线（收盘价 < 开盘价）
    
    # 1. 锤子线（Hammer）：下影线长，实体小，上影线短或没有
    # 特征：下影线 >= 2倍实体，上影线 <= 实体，实体在价格区间上半部分
    hammer_condition = (
        (lower_shadow >= 2 * body) &
        (upper_shadow <= body) &
        (body_size < 0.03) &  # 实体相对较小
        (close > (high + low) / 2)  # 收盘价在价格区间上半部分
    )
    patterns["pattern_hammer"] = hammer_condition.astype(int)
    
    # 2. 上吊线（Hanging Man）：形态与锤子线相同，但出现在上升趋势中
    # 特征：与锤子线相同，但收盘价在价格区间下半部分
    hanging_man_condition = (
        (lower_shadow >= 2 * body) &
        (upper_shadow <= body) &
        (body_size < 0.03) &
        (close < (high + low) / 2)  # 收盘价在价格区间下半部分
    )
    patterns["pattern_hanging_man"] = hanging_man_condition.astype(int)
    
    # 3. 看涨吞没形态（Bullish Engulfing）：前一根是阴线，当前是阳线，且当前实体完全包含前一根实体
    prev_open = open.shift(1)
    prev_close = close.shift(1)
    prev_is_bearish = prev_close < prev_open
    current_is_bullish = is_bullish
    current_engulfs = (open < prev_close) & (close > prev_open)
    bullish_engulfing = prev_is_bearish & current_is_bullish & current_engulfs
    patterns["pattern_bullish_engulfing"] = bullish_engulfing.astype(int)
    
    # 4. 看跌吞没形态（Bearish Engulfing）：前一根是阳线，当前是阴线，且当前实体完全包含前一根实体
    prev_is_bullish = prev_close > prev_open
    current_is_bearish = is_bearish
    current_engulfs_bearish = (open > prev_close) & (close < prev_open)
    bearish_engulfing = prev_is_bullish & current_is_bearish & current_engulfs_bearish
    patterns["pattern_bearish_engulfing"] = bearish_engulfing.astype(int)
    
    # 5. 十字星（Doji）：开盘价和收盘价非常接近，实体很小
    doji_condition = body_size < 0.001  # 实体非常小
    patterns["pattern_doji"] = doji_condition.astype(int)
    
    # 6. 三只乌鸦（Three Black Crows）：连续三根阴线，每根都比前一根低
    prev2_close = close.shift(2)
    prev2_open = open.shift(2)
    three_black_crows = (
        is_bearish &
        prev_is_bearish &
        (prev_close < prev_open) &
        (prev2_close < prev2_open) &
        (close < prev_close) &
        (prev_close < prev2_close)
    )
    patterns["pattern_three_black_crows"] = three_black_crows.astype(int)
    
    # 7. 三白兵（Three White Soldiers）：连续三根阳线，每根都比前一根高
    three_white_soldiers = (
        is_bullish &
        prev_is_bullish &
        (prev_close > prev_open) &
        (prev2_close > prev2_open) &
        (close > prev_close) &
        (prev_close > prev2_close)
    )
    patterns["pattern_three_white_soldiers"] = three_white_soldiers.astype(int)
    
    # 8. 晨星（Morning Star）：第一根阴线，第二根小实体（可能是十字星），第三根阳线
    prev2_is_bearish = prev2_close < prev2_open
    prev_body_size = (prev_close - prev_open).abs() / prev_close
    morning_star = (
        prev2_is_bearish &
        (prev_body_size < 0.01) &  # 中间K线实体很小
        is_bullish &
        (close > (prev2_open + prev2_close) / 2)  # 第三根阳线收盘价超过第一根中点
    )
    patterns["pattern_morning_star"] = morning_star.astype(int)
    
    # 9. 暮星（Evening Star）：第一根阳线，第二根小实体（可能是十字星），第三根阴线
    prev2_is_bullish = prev2_close > prev2_open
    evening_star = (
        prev2_is_bullish &
        (prev_body_size < 0.01) &  # 中间K线实体很小
        is_bearish &
        (close < (prev2_open + prev2_close) / 2)  # 第三根阴线收盘价低于第一根中点
    )
    patterns["pattern_evening_star"] = evening_star.astype(int)
    
    # 10. 乌云盖顶（Dark Cloud Cover）：第一根阳线，第二根阴线开盘价高于第一根最高价，收盘价低于第一根中点
    prev_high = high.shift(1)
    dark_cloud = (
        prev_is_bullish &
        is_bearish &
        (open > prev_high) &
        (close < (prev_open + prev_close) / 2)
    )
    patterns["pattern_dark_cloud"] = dark_cloud.astype(int)
    
    # 11. 刺透形态（Piercing Pattern）：第一根阴线，第二根阳线开盘价低于第一根最低价，收盘价高于第一根中点
    prev_low = low.shift(1)
    piercing = (
        prev_is_bearish &
        is_bullish &
        (open < prev_low) &
        (close > (prev_open + prev_close) / 2)
    )
    patterns["pattern_piercing"] = piercing.astype(int)
    
    # 填充NaN值为0（未识别）
    patterns = patterns.fillna(0)
    
    return patterns

